#!/usr/bin/env python3
# coding=utf-8

"""
Test cert_util functionality in coordinator_server.py
"""
import os
import tempfile
import shutil
import pytest
from datetime import datetime, timedelta, timezone
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa

from motor.coordinator.api_server.coordinator_server import SSLConfig
from motor.utils.cert_util import CoordinatorCertUtil, CertUtil
from motor.utils.logger import get_logger

logger = get_logger(__name__)



def create_test_certificates():
    """Create test certificate files using cryptography library"""
    # Create temporary directory
    temp_dir = tempfile.mkdtemp()
    logger.info(f"Creating test certificate directory: {temp_dir}")
    
    # Create CA private key
    ca_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=3072,
    )
    
    # Create CA certificate
    subject = issuer = x509.Name([
        x509.NameAttribute(NameOID.COMMON_NAME, "Test CA"),
    ])
    
    ca_cert = x509.CertificateBuilder().subject_name(
        subject
    ).issuer_name(
        issuer
    ).public_key(
        ca_key.public_key()
    ).serial_number(
        x509.random_serial_number()
    ).not_valid_before(
        datetime.now(timezone.utc)
    ).not_valid_after(
        datetime.now(timezone.utc) + timedelta(days=365)
    ).add_extension(
        x509.BasicConstraints(ca=True, path_length=None), critical=True,
    ).add_extension(
        x509.KeyUsage(
            digital_signature=True,
            content_commitment=False,
            key_encipherment=False,
            data_encipherment=False,
            key_agreement=False,
            key_cert_sign=True,
            crl_sign=True,
            encipher_only=False,
            decipher_only=False,
        ), critical=True,
    ).sign(ca_key, hashes.SHA256())
    
    # Create server private key
    server_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=3072,
    )
    
    # Create server certificate
    server_subject = x509.Name([
        x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
    ])
    
    server_cert = x509.CertificateBuilder().subject_name(
        server_subject
    ).issuer_name(
        ca_cert.subject
    ).public_key(
        server_key.public_key()
    ).serial_number(
        x509.random_serial_number()
    ).not_valid_before(
        datetime.now(timezone.utc)
    ).not_valid_after(
        datetime.now(timezone.utc) + timedelta(days=365)
    ).sign(ca_key, hashes.SHA256())
    
    ca_cert_path = os.path.join(temp_dir, "ca_cert.pem")
    server_cert_path = os.path.join(temp_dir, "server_cert.pem")
    server_key_path = os.path.join(temp_dir, "server_key.pem")
    
    # Write CA certificate
    with open(ca_cert_path, "wb") as f:
        f.write(ca_cert.public_bytes(serialization.Encoding.PEM))
    
    # Write server certificate
    with open(server_cert_path, "wb") as f:
        f.write(server_cert.public_bytes(serialization.Encoding.PEM))
    
    # Write server private key
    with open(server_key_path, "wb") as f:
        f.write(server_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        ))
    
    # Set permissions
    os.chmod(temp_dir, 0o700)
    for file_path in [ca_cert_path, server_cert_path, server_key_path]:
        os.chmod(file_path, 0o600)
    
    return {
        "ca_cert": ca_cert_path,
        "server_cert": server_cert_path,
        "server_key": server_key_path,
        "temp_dir": temp_dir,
        "ca_key_obj": ca_key,
        "ca_cert_obj": ca_cert
    }


def create_test_crl(ca_key, ca_cert, revoked_serial_numbers=None, next_update_days=30, temp_dir=None):
    """
    Create a test CRL file
    
    Args:
        ca_key: CA private key object
        ca_cert: CA certificate object
        revoked_serial_numbers: List of serial numbers to revoke (optional)
        next_update_days: Days until next CRL update (default: 30)
        temp_dir: Temporary directory to save CRL (if None, creates new one)
        
    Returns:
        Dict with 'crl_path' and 'temp_dir' keys
    """
    if temp_dir is None:
        temp_dir = tempfile.mkdtemp()
    crl_path = os.path.join(temp_dir, "test_crl.pem")
    
    # Create CRL builder
    builder = x509.CertificateRevocationListBuilder()
    builder = builder.issuer_name(ca_cert.subject)
    
    # Handle expired CRL case (next_update_days < 0)
    if next_update_days < 0:
        # For expired CRL, set last_update in the past and next_update before last_update
        last_update_time = datetime.now(timezone.utc) + timedelta(days=next_update_days - 1)
        next_update_time = datetime.now(timezone.utc) + timedelta(days=next_update_days)
    else:
        # Normal case: last_update is now, next_update is in the future
        last_update_time = datetime.now(timezone.utc)
        next_update_time = datetime.now(timezone.utc) + timedelta(days=next_update_days)
    
    builder = builder.last_update(last_update_time)
    builder = builder.next_update(next_update_time)
    
    # Add revoked certificates if any
    if revoked_serial_numbers:
        for serial_num in revoked_serial_numbers:
            revoked_cert = x509.RevokedCertificateBuilder().serial_number(
                serial_num
            ).revocation_date(
                datetime.now(timezone.utc)
            ).build()
            builder = builder.add_revoked_certificate(revoked_cert)
    
    # Sign CRL with CA private key
    crl = builder.sign(ca_key, hashes.SHA256())
    
    # Write CRL to file
    with open(crl_path, "wb") as f:
        f.write(crl.public_bytes(serialization.Encoding.PEM))
    
    os.chmod(crl_path, 0o600)
    
    return {"crl_path": crl_path, "temp_dir": temp_dir}


def create_other_ca():
    """Create another CA certificate and key (for mismatched CA tests)"""
    other_ca_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=3072,
    )
    
    other_ca_subject = x509.Name([
        x509.NameAttribute(NameOID.COMMON_NAME, "Other CA"),
    ])
    
    other_ca_cert = x509.CertificateBuilder().subject_name(
        other_ca_subject
    ).issuer_name(
        other_ca_subject
    ).public_key(
        other_ca_key.public_key()
    ).serial_number(
        x509.random_serial_number()
    ).not_valid_before(
        datetime.now(timezone.utc)
    ).not_valid_after(
        datetime.now(timezone.utc) + timedelta(days=365)
    ).add_extension(
        x509.BasicConstraints(ca=True, path_length=None), critical=True,
    ).add_extension(
        x509.KeyUsage(
            digital_signature=True,
            content_commitment=False,
            key_encipherment=False,
            data_encipherment=False,
            key_agreement=False,
            key_cert_sign=True,
            crl_sign=True,
            encipher_only=False,
            decipher_only=False,
        ), critical=True,
    ).sign(other_ca_key, hashes.SHA256())
    
    return other_ca_key, other_ca_cert


# ============================================================================
# Fixtures
# ============================================================================

@pytest.fixture
def test_certificates():
    """Fixture to create and clean up test certificates"""
    test_certs = create_test_certificates()
    yield test_certs
    # Clean up test certificates
    shutil.rmtree(test_certs["temp_dir"])


# ============================================================================
# Basic functionality tests
# ============================================================================

def test_cert_util_validation(test_certificates):
    """Test cert_util certificate validation functionality"""
    logger.info("=== Testing cert_util certificate validation functionality ===")
    
    test_certs = test_certificates
    
    # Test certificate information query
    cert_info = CoordinatorCertUtil.query_certificate_info(test_certs["server_cert"])
    logger.info(f"Certificate information query succeeded: {cert_info}")
    assert cert_info is not None, "Certificate information query should succeed"
    
    # Test certificate chain validation
    validation_result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file=test_certs["ca_cert"],
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"]
    )
    logger.info(f"Certificate chain validation result: {validation_result}")
    assert validation_result is True, "Certificate chain validation should succeed"
    
    # Test SSL context creation
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"]
    )
    logger.info(f"SSL context created successfully: {ssl_context is not None}")
    assert ssl_context is not None, "SSL context should be created successfully"


def test_coordinator_server_ssl_config(test_certificates):
    """Test Coordinator server SSL configuration"""
    logger.info("=== Testing Coordinator server SSL configuration ===")
    
    test_certs = test_certificates
    
    # Create SSL configuration
    ssl_config = SSLConfig()
    ssl_config.enabled = True
    ssl_config.cert_file = test_certs["server_cert"]
    ssl_config.key_file = test_certs["server_key"]
    ssl_config.ca_file = test_certs["ca_cert"]
    
    logger.info("Coordinator server SSL configuration created successfully")
    
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=ssl_config.cert_file,
        key_file=ssl_config.key_file,
        ca_file=ssl_config.ca_file,
        password=ssl_config.password
    )
    
    assert ssl_context is not None, "SSL context should be created successfully"
    logger.info("SSL context created successfully, cert_util works properly in coordinator_server")


def test_ssl_disabled_mode():
    """Test SSL disabled mode"""
    logger.info("=== Testing SSL disabled mode ===")
    
    # Create SSL configuration (disable SSL)
    ssl_config = SSLConfig()
    ssl_config.enabled = False
    
    logger.info("Coordinator server configuration in SSL disabled mode created successfully")
    assert ssl_config.enabled is False, "SSL should be disabled"


# ============================================================================
# SSL context creation tests
# ============================================================================

def test_create_ssl_context_basic(test_certificates):
    """Test basic SSL context creation"""
    logger.info("=== Testing basic SSL context creation ===")
    
    test_certs = test_certificates
    
    # Test with valid certificates
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"]
    )
    assert ssl_context is not None, "SSL context should be created successfully"
    logger.info("SSL context created successfully")
    
    # Test with password
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"],
        password=""
    )
    assert ssl_context is not None, "SSL context should be created with empty password"
    
    # Test with password parameter (even though key is not encrypted)
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"],
        password="test_password"
    )
    assert ssl_context is not None, "SSL context should handle password parameter"


def test_create_ssl_context_no_client_cert(test_certificates):
    """Test create_ssl_context_no_client_cert method"""
    logger.info("=== Testing create_ssl_context_no_client_cert ===")
    
    test_certs = test_certificates
    
    # Test with valid certificates (no client cert verification)
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"]
    )
    assert ssl_context is not None, "SSL context should be created successfully"
    logger.info("SSL context created successfully without client cert verification")
    
    # Test without CA file (optional)
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=""
    )
    assert ssl_context is not None, "SSL context should be created without CA file"
    
    # Test with password
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        ca_file=test_certs["ca_cert"],
        password=""
    )
    assert ssl_context is not None, "SSL context should be created with empty password"


def test_create_ssl_context_error_handling():
    """Test SSL context creation error handling"""
    logger.info("=== Testing SSL context creation error handling ===")
    
    # Test with None values
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file=None,
        key_file=None,
        ca_file=None
    )
    assert ssl_context is None, "None values should return None"
    
    # Test with empty string values
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file="",
        key_file="",
        ca_file=""
    )
    assert ssl_context is None, "Empty strings should return None"
    
    # Test non-existent certificate files
    ssl_context = CoordinatorCertUtil.create_ssl_context(
        cert_file="/nonexistent/cert.pem",
        key_file="/nonexistent/key.pem",
        ca_file="/nonexistent/ca.pem"
    )
    assert ssl_context is None, "Non-existent certificate files should return None"
    
    # Test create_ssl_context_no_client_cert with None values
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file=None,
        key_file=None,
        ca_file=None
    )
    assert ssl_context is None, "None values should return None"
    
    # Test with empty key_file
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file="/nonexistent/cert.pem",
        key_file="",
        ca_file=""
    )
    assert ssl_context is None, "Empty key_file should return None"
    
    # Test with non-existent certificate files
    ssl_context = CoordinatorCertUtil.create_ssl_context_no_client_cert(
        cert_file="/nonexistent/cert.pem",
        key_file="/nonexistent/key.pem",
        ca_file=""
    )
    assert ssl_context is None, "Non-existent certificate files should return None"
    
    logger.info("SSL context creation error handling works correctly")


# ============================================================================
# Certificate info query tests
# ============================================================================

def test_cert_info_query(test_certificates):
    """Test certificate and CRL info query functionality"""
    logger.info("=== Testing certificate info query ===")
    
    test_certs = test_certificates
    
    # Test certificate information query
    cert_info = CoordinatorCertUtil.query_certificate_info(test_certs["server_cert"])
    logger.info(f"Certificate information query succeeded: {cert_info}")
    assert cert_info is not None, "Certificate information query should succeed"
    
    # Test with non-existent certificate file
    cert_info = CoordinatorCertUtil.query_certificate_info("/nonexistent/cert.pem")
    assert cert_info == {}, "Certificate info query should return empty dict for non-existent file"
    
    # Test with invalid certificate file
    temp_dir = tempfile.mkdtemp()
    try:
        invalid_cert_path = os.path.join(temp_dir, "invalid_cert.pem")
        with open(invalid_cert_path, "w") as f:
            f.write("invalid certificate content")
        
        cert_info = CoordinatorCertUtil.query_certificate_info(invalid_cert_path)
        assert cert_info == {}, "Certificate info query should return empty dict for invalid file"
    finally:
        shutil.rmtree(temp_dir)
    
    # Test CRL info query with non-existent file
    crl_info = CoordinatorCertUtil.query_crl_info("/nonexistent/crl.pem")
    assert crl_info == [], "CRL info query should return empty list for non-existent file"
    logger.info("Certificate and CRL info query works correctly")


# ============================================================================
# Certificate chain validation tests
# ============================================================================

def test_validate_certificate_chain(test_certificates):
    """Test certificate chain validation"""
    logger.info("=== Testing certificate chain validation ===")
    
    test_certs = test_certificates
    
    # Test basic certificate chain validation
    validation_result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file=test_certs["ca_cert"],
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"]
    )
    assert validation_result is True, "Certificate chain validation should succeed"
    
    # Test without CRL (should work)
    validation_result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file=test_certs["ca_cert"],
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        crl_file=None
    )
    assert validation_result is True, "Certificate chain validation should succeed without CRL"
    
    # Test with non-existent CRL file
    validation_result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file=test_certs["ca_cert"],
        cert_file=test_certs["server_cert"],
        key_file=test_certs["server_key"],
        crl_file="/nonexistent/crl.pem"
    )
    # Should succeed if CRL file doesn't exist (optional)
    logger.info("Certificate chain validation handled non-existent CRL file")
    
    # Test error handling
    result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file="/nonexistent/ca.pem",
        cert_file="/nonexistent/cert.pem",
        key_file="/nonexistent/key.pem"
    )
    assert result is False, "Non-existent files should return False"
    
    result = CoordinatorCertUtil.validate_certificate_chain(
        ca_file="",
        cert_file="",
        key_file=""
    )
    assert result is False, "Empty strings should return False"
    logger.info("Certificate chain validation works correctly")


# ============================================================================
# construct_cert_context tests
# ============================================================================

def test_construct_cert_context(test_certificates):
    """Test construct_cert_context method with strict validation"""
    logger.info("=== Testing construct_cert_context method ===")
    
    test_certs = test_certificates
    
    # Note: This test may fail if directory permissions are not 700
    # We'll skip it if it fails due to permission issues
    try:
        # Test with valid certificates
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_passwd": ""
        }
        
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        # May succeed or fail depending on certificate validation
        logger.info(f"construct_cert_context result: {ssl_context is not None}")
    except Exception as e:
        logger.info(f"construct_cert_context failed (expected for some cases): {e}")




# ============================================================================
# CRL validation tests
# ============================================================================

def test_validate_revoke_list(test_certificates):
    """Test validate_revoke_list with various CRL scenarios"""
    logger.info("=== Testing validate_revoke_list ===")
    
    test_certs = test_certificates
    
    # Test with valid CRL (empty list, valid next_update)
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    result = CertUtil.validate_revoke_list(crl_info["crl_path"])
    assert result is True, "Valid CRL should return True"
    
    # Test with CRL containing revoked certificates
    revoked_serials = [12345, 67890]
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=revoked_serials,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    result = CertUtil.validate_revoke_list(crl_info["crl_path"])
    assert result is True, "CRL with revoked certificates should return True"
    
    # Test with expired CRL
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=None,
        next_update_days=-1,  # Expired
        temp_dir=test_certs["temp_dir"]
    )
    result = CertUtil.validate_revoke_list(crl_info["crl_path"])
    assert result is False, "Expired CRL should return False"
    
    # Test with non-existent file
    result = CertUtil.validate_revoke_list("/nonexistent/crl.pem")
    assert result is False, "Non-existent file should return False"
    
    # Test with invalid CRL file
    temp_dir = tempfile.mkdtemp()
    try:
        invalid_crl_path = os.path.join(temp_dir, "invalid_crl.pem")
        with open(invalid_crl_path, "w") as f:
            f.write("invalid CRL content")
        
        result = CertUtil.validate_revoke_list(invalid_crl_path)
        assert result is False, "Invalid CRL file should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    logger.info("validate_revoke_list works correctly")


def test_validate_ca_crl(test_certificates):
    """Test validate_ca_crl with various scenarios"""
    logger.info("=== Testing validate_ca_crl ===")
    
    test_certs = test_certificates
    
    # Test with valid CRL signed by matching CA
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    result = CertUtil.validate_ca_crl(test_certs["ca_cert"], crl_info["crl_path"])
    assert result is True, "Valid CRL signed by matching CA should return True"
    
    # Test with CRL signed by different CA
    other_ca_key, other_ca_cert = create_other_ca()
    crl_info = create_test_crl(
        ca_key=other_ca_key,
        ca_cert=other_ca_cert,
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    result = CertUtil.validate_ca_crl(test_certs["ca_cert"], crl_info["crl_path"])
    assert result is False, "CRL signed by different CA should return False"
    
    # Test with non-existent files
    result = CertUtil.validate_ca_crl("/nonexistent/ca.pem", "/nonexistent/crl.pem")
    assert result is False, "Non-existent files should return False"
    
    # Test with invalid CRL file
    temp_dir = tempfile.mkdtemp()
    try:
        invalid_crl_path = os.path.join(temp_dir, "invalid_crl.pem")
        with open(invalid_crl_path, "w") as f:
            f.write("invalid CRL content")
        
        result = CertUtil.validate_ca_crl("/nonexistent/ca.pem", invalid_crl_path)
        assert result is False, "Invalid CRL file should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    logger.info("validate_ca_crl works correctly")


# ============================================================================
# construct_cert_context tests
# ============================================================================

def test_construct_cert_context_comprehensive(test_certificates):
    """Test construct_cert_context with various scenarios"""
    logger.info("=== Testing construct_cert_context comprehensive scenarios ===")
    
    test_certs = test_certificates
    
    # Test with valid certificates (no CRL)
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_passwd": ""
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        logger.info(f"construct_cert_context without CRL result: {ssl_context is not None}")
    except Exception as e:
        logger.info(f"construct_cert_context failed (may be due to directory permissions): {e}")
    
    # Test with valid CRL
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_crl": crl_info["crl_path"],
            "tls_passwd": ""
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        assert ssl_context is not None, "construct_cert_context should succeed with valid CRL"
        
        # Verify context attributes
        assert hasattr(ssl_context, 'cert_file'), "SSL context should have cert_file attribute"
        assert hasattr(ssl_context, 'key_file'), "SSL context should have key_file attribute"
        assert hasattr(ssl_context, 'ca_file'), "SSL context should have ca_file attribute"
    except Exception as e:
        logger.info(f"construct_cert_context failed (may be due to directory permissions): {e}")
    
    # Test with valid CRL containing revoked certificates
    revoked_serials = [12345, 67890]
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=revoked_serials,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_crl": crl_info["crl_path"],
            "tls_passwd": ""
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        assert ssl_context is not None, "construct_cert_context should succeed with CRL containing revoked certs"
    except Exception as e:
        logger.info(f"construct_cert_context failed (may be due to directory permissions): {e}")
    
    # Test with invalid CRL file
    temp_dir = tempfile.mkdtemp()
    invalid_crl_path = os.path.join(temp_dir, "invalid_crl.pem")
    with open(invalid_crl_path, "w") as f:
        f.write("invalid CRL content")
    
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_crl": invalid_crl_path,
            "tls_passwd": ""
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        assert ssl_context is None, "construct_cert_context should fail with invalid CRL file"
    except Exception as e:
        logger.info(f"construct_cert_context failed as expected: {e}")
    finally:
        shutil.rmtree(temp_dir)
    
    # Test with mismatched CRL (signed by different CA)
    other_ca_key, other_ca_cert = create_other_ca()
    crl_info = create_test_crl(
        ca_key=other_ca_key,
        ca_cert=other_ca_cert,
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_crl": crl_info["crl_path"],
            "tls_passwd": ""
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        assert ssl_context is None, "construct_cert_context should fail with mismatched CRL"
    except Exception as e:
        logger.info(f"construct_cert_context failed as expected: {e}")
    
    # Test with password
    try:
        config = {
            "ca_cert": test_certs["ca_cert"],
            "tls_cert": test_certs["server_cert"],
            "tls_key": test_certs["server_key"],
            "tls_passwd": "test_password"
        }
        ssl_context = CoordinatorCertUtil.construct_cert_context(config)
        assert ssl_context is not None, "construct_cert_context should handle password parameter"
    except Exception as e:
        logger.info(f"construct_cert_context failed (may be due to directory permissions): {e}")
    
    # Test error handling
    ssl_context = CoordinatorCertUtil.construct_cert_context({})
    assert ssl_context is None, "Empty config should return None"
    
    invalid_config = {
        "ca_cert": "/nonexistent/ca.pem",
        "tls_cert": "/nonexistent/cert.pem"
        # Missing tls_key
    }
    ssl_context = CoordinatorCertUtil.construct_cert_context(invalid_config)
    assert ssl_context is None, "Missing required keys should return None"
    logger.info("construct_cert_context comprehensive test completed")


# ============================================================================
# validate_cert_and_key tests
# ============================================================================

def test_validate_cert_and_key_comprehensive(test_certificates):
    """Test validate_cert_and_key with comprehensive scenarios"""
    logger.info("=== Testing validate_cert_and_key comprehensive scenarios ===")
    
    test_certs = test_certificates
    
    # Test with valid certificates (without CA)
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"]
    )
    assert result is True, "validate_cert_and_key should succeed with valid certificates"
    
    # Test with valid certificates (with CA)
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        ca_crt_path=test_certs["ca_cert"]
    )
    assert result is True, "validate_cert_and_key should succeed with valid CA certificate"
    
    # Test with empty/None CA (optional)
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        ca_crt_path=""
    )
    assert result is True, "Empty CA certificate path should be treated as optional"
    
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        ca_crt_path=None
    )
    assert result is True, "None CA certificate should be treated as optional"
    
    # Test with password
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        plain_text=b""
    )
    assert result is True, "validate_cert_and_key should work with empty password"
    
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        plain_text=b"test_password"
    )
    assert result is True, "validate_cert_and_key should handle password parameter gracefully"
    
    # Test error handling: None values
    result = CertUtil.validate_cert_and_key(
        server_crt_path=None,
        server_key_path="/nonexistent/key.pem"
    )
    assert result is False, "None server_crt_path should return False"
    
    result = CertUtil.validate_cert_and_key(
        server_crt_path="/nonexistent/cert.pem",
        server_key_path=None
    )
    assert result is False, "None server_key_path should return False"
    
    # Test error handling: empty strings
    result = CertUtil.validate_cert_and_key(
        server_crt_path="",
        server_key_path="/nonexistent/key.pem"
    )
    assert result is False, "Empty server_crt_path should return False"
    
    result = CertUtil.validate_cert_and_key(
        server_crt_path="/nonexistent/cert.pem",
        server_key_path=""
    )
    assert result is False, "Empty server_key_path should return False"
    
    # Test error handling: non-existent files
    result = CertUtil.validate_cert_and_key(
        server_crt_path="/nonexistent/server_cert.pem",
        server_key_path="/nonexistent/server_key.pem"
    )
    assert result is False, "Non-existent certificate file should return False"
    
    # Test error handling: empty files
    temp_dir = tempfile.mkdtemp()
    try:
        empty_cert_path = os.path.join(temp_dir, "empty_cert.pem")
        empty_key_path = os.path.join(temp_dir, "empty_key.pem")
        with open(empty_cert_path, "w") as f:
            pass
        with open(empty_key_path, "w") as f:
            pass
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=empty_cert_path,
            server_key_path=empty_key_path
        )
        assert result is False, "Empty files should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    # Test error handling: invalid formats
    temp_dir = tempfile.mkdtemp()
    try:
        invalid_cert_path = os.path.join(temp_dir, "invalid_cert.pem")
        invalid_key_path = os.path.join(temp_dir, "invalid_key.pem")
        
        with open(invalid_cert_path, "w") as f:
            f.write("This is not a valid certificate")
        with open(invalid_key_path, "w") as f:
            f.write("-----BEGIN PRIVATE KEY-----\ninvalid\n-----END PRIVATE KEY-----\n")
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=invalid_cert_path,
            server_key_path=invalid_key_path
        )
        assert result is False, "Invalid certificate format should return False"
        
        # Test with valid cert but invalid key
        valid_cert_path = os.path.join(temp_dir, "valid_cert.pem")
        with open(valid_cert_path, "w") as f:
            f.write("-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----\n")
        with open(invalid_key_path, "w") as f:
            f.write("This is not a valid private key")
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=valid_cert_path,
            server_key_path=invalid_key_path
        )
        assert result is False, "Invalid key format should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    # Test error handling: mismatched cert and key
    temp_dir = tempfile.mkdtemp()
    try:
        other_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=3072,
        )
        other_key_path = os.path.join(temp_dir, "other_key.pem")
        with open(other_key_path, "wb") as f:
            f.write(other_key.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.PKCS8,
                encryption_algorithm=serialization.NoEncryption()
            ))
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=test_certs["server_cert"],
            server_key_path=other_key_path
        )
        assert result is False, "Mismatched certificate and key should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    # Test error handling: CA-related errors
    result = CertUtil.validate_cert_and_key(
        server_crt_path=test_certs["server_cert"],
        server_key_path=test_certs["server_key"],
        ca_crt_path="/nonexistent/ca_cert.pem"
    )
    assert result is False, "Non-existent CA certificate should return False"
    
    temp_dir = tempfile.mkdtemp()
    try:
        invalid_ca_path = os.path.join(temp_dir, "invalid_ca.pem")
        with open(invalid_ca_path, "w") as f:
            f.write("This is not a valid CA certificate")
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=test_certs["server_cert"],
            server_key_path=test_certs["server_key"],
            ca_crt_path=invalid_ca_path
        )
        assert result is False, "Invalid CA certificate format should return False"
        
        # Test with mismatched CA
        other_ca_key, other_ca_cert = create_other_ca()
        other_ca_path = os.path.join(temp_dir, "other_ca.pem")
        with open(other_ca_path, "wb") as f:
            f.write(other_ca_cert.public_bytes(serialization.Encoding.PEM))
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=test_certs["server_cert"],
            server_key_path=test_certs["server_key"],
            ca_crt_path=other_ca_path
        )
        assert result is False, "Mismatched CA certificate should return False"
        
        # Test with empty CA file
        empty_ca_path = os.path.join(temp_dir, "empty_ca.pem")
        with open(empty_ca_path, "w") as f:
            pass
        
        result = CertUtil.validate_cert_and_key(
            server_crt_path=test_certs["server_cert"],
            server_key_path=test_certs["server_key"],
            ca_crt_path=empty_ca_path
        )
        assert result is False, "Empty CA certificate file should return False"
    finally:
        shutil.rmtree(temp_dir)
    
    logger.info("validate_cert_and_key comprehensive test completed")


def test_query_crl_info_cases(test_certificates):
    """Cover query_crl_info: CRL with revoked entries and empty CRL cases"""
    logger.info("=== Testing query_crl_info cases ===")

    test_certs = test_certificates

    # 1) Generate a CRL that contains revoked entries
    revoked_serials = [11111, 22222]
    crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=revoked_serials,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    items = CoordinatorCertUtil.query_crl_info(crl_info["crl_path"])
    assert isinstance(items, list), "query_crl_info should return a list"
    assert len(items) == len(revoked_serials), "Count of revoked entries should match"
    for item in items:
        assert "Serial Number" in item and "Revoked Reason" in item and "Revocation Date" in item
    returned_serials = {item["Serial Number"] for item in items}
    assert returned_serials == {str(s) for s in revoked_serials}, "Serial numbers should match generated CRL"

    # 2) Generate an empty CRL (no revoked entries)
    empty_crl_info = create_test_crl(
        ca_key=test_certs["ca_key_obj"],
        ca_cert=test_certs["ca_cert_obj"],
        revoked_serial_numbers=None,
        next_update_days=30,
        temp_dir=test_certs["temp_dir"]
    )
    empty_items = CoordinatorCertUtil.query_crl_info(empty_crl_info["crl_path"])
    assert empty_items == [], "Empty CRL should return an empty list"


def test_construct_cert_context_with_invalid_crl_path(test_certificates):
    """When config includes an invalid CRL path, construct_cert_context should return None"""
    logger.info("=== Testing construct_cert_context with invalid CRL path ===")

    test_certs = test_certificates

    config = {
        "ca_cert": test_certs["ca_cert"],
        "tls_cert": test_certs["server_cert"],
        "tls_key": test_certs["server_key"],
        "tls_crl": os.path.join(test_certs["temp_dir"], "not_exist_crl.pem"),
        "tls_passwd": ""
    }

    # Directory permissions may not satisfy strict checks on different platforms; keep returning None per existing cases
    ssl_context = CoordinatorCertUtil.construct_cert_context(config)
    assert ssl_context is None, "Invalid CRL path should lead to returning None"